/*
This file is part of cdbnlib.

    cdbnlib is free software: you can redistribute it and/or modify it under
    the terms of the GNU Lesser General Public License as published by the Free
    Software Foundation, either version 3 of the License, or (at your option)
    any later version.

    cdbnlib is distributed in the hope that it will be useful, but WITHOUT ANY
    WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
    more details.

    You should have received a copy of the GNU Lesser General Public License
    along with cdbnlib.  If not, see <http://www.gnu.org/licenses/>.
*/


#include "cdbnlib.h"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>

/* This function creates a new layer of neurons
 *
 * layer points to an already allocated struct of
 * the type dl_layer_t
 *
 * count is the number of neurons
 */
void dl_create_layer(dl_layer_t *layer, int count)
{
	// Count of neurons
	layer->count = count;

	// Allocate the memory for the bias
	if ((layer->bias = (double *)malloc(count * sizeof(double))) == NULL)
	{
		perror("dl_new_layer bias malloc error");
		exit(2);
	}

	// Allocate the memory for the prob
	if ((layer->prob = (double *)malloc(count * sizeof(double))) == NULL)
	{
		perror("dl_new_layer prob malloc error");
		exit(2);
	}

	// Allocate the memory for the negative learning phase accumulators
	if ((layer->sample = (char *)malloc(count * sizeof(char))) == NULL)
	{
		perror("dl_new_layer sample malloc error");
		exit(2);
	}

	// Init the biases and probs
	dl_init_layer(layer);
}

/* This function initializes the biases and probs
 * of a layer
 */
void dl_init_layer(dl_layer_t *layer)
{
	memset(layer->bias, 0, layer->count*sizeof(double));
	memset(layer->prob, 0, layer->count*sizeof(double));
}

/* Frees the memory of allocated by the structure
 *
 * Attention, it does not free the structure itself
 */
void dl_del_layer(dl_layer_t *layer)
{
	free(layer->bias);
	free(layer->prob);
	free(layer->sample);
}

/* This function gets a sample from the given layer
 *
 * Both layer and sample are supposed to be allocated
 * and layer is supposed to have been created as well
 */
void dl_layer_get_sample(dl_layer_t *layer)
{
	dl_layer_get_sample_with_prob(layer,layer->prob);
}

/* This function gets a sample from the given layer
 * according to the probabilities passed as argument
 *
 * Both layer and sample are supposed to be allocated
 * and layer is supposed to have been created as well
 */
void dl_layer_get_sample_with_prob(dl_layer_t *layer, double *prob)
{
	int i;
	for (i = 0 ; i < layer->count ; ++i)
	{
		// Assigning the truth value of the <= comparison
		// means layer->sample[i] will be 0 if false
		layer->sample[i] = (random() <= (prob[i]*RAND_MAX));
	}
}

